package com.ruoyi.quartz.service.impl;

import com.ruoyi.bus.domain.WitAppoint;
import com.ruoyi.bus.domain.WitBus;
import com.ruoyi.bus.domain.WitPlan;
import com.ruoyi.bus.domain.WitRoute;
import com.ruoyi.bus.service.*;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.quartz.service.IPlanBusService;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 班车执行计划业务
 */
@Slf4j
@Service
public class PlanBusServiceImpl implements IPlanBusService {

    @Autowired
    private IWitAppointService appointService;
    @Autowired
    private IWitRouteService routeService;
    @Autowired
    private IWitBusService busService;
    @Autowired
    private IWitPlanService planService;
    @Autowired
    private ISysConfigService configService;
    @Autowired
    private ISysUserService userService;
    @Autowired
    private RedisCache redisCache;

    private ThreadLocal myThreadLocal = new ThreadLocal();

    /**
     * 排班分早班次和晚班次,本次只处理早班次
     * 1、遍历所有路线
     * 2、按照班次,预约状态查找所有今日预约总数
     *
     *
     * 每条路线可以有多个排班
     * 每个车只能有一个排班
     */
    @Transactional
    public void plan(String driveTimes, Date date){
        /*Date date = new Date();*/
        List<WitRoute> witRouteList = this.getAllRoute();
        WitPlan plan = null;
        for(WitRoute witRoute : witRouteList){

            List<WitAppoint> witAppointList = this.getAllAppoint(witRoute.getRouteId(), driveTimes, date);//该路线所有预约的人
            if(witAppointList.size() == 0){
                continue;
            }
            if(this.isPlan(witRoute.getRouteId(), driveTimes, date)){
                continue;
            }
            List<WitBus> needBusCount = this.listNeedBusCount(witAppointList);//本次路线一共需要多少辆车
            if(needBusCount.size() == 0){//路线未分配车，该路线状态置为4（车辆不足）
                for(WitAppoint witAppoint : witAppointList){
                    witAppoint.setAppointStatus(4);
                    appointService.updateWitAppoint(witAppoint);
                }
                continue;
            }
            this.averageBus(needBusCount, witAppointList);//给Bus填充预约数据,可能存在预约人数大于车辆最大座位数
            for(WitBus witBus : needBusCount){
                plan = new WitPlan();
                plan.setAppointCount(witBus.getWitAppointList().size());//预约数
                plan.setBusId(witBus.getBusId());
                plan.setBusModel(witBus.getBusModel());
                plan.setBusNumber(witBus.getBusNumber());
                plan.setDriverUserId(witBus.getUserId());
                SysUser user = getDriverUser(witBus.getUserId());
                plan.setDriverUserName(user.getUserName());
                plan.setDriveTime(driveTimes);
                plan.setRouteId(witRoute.getRouteId());
                plan.setRouteName(witRoute.getRouteName());
                plan.setTempAppointCount(0);
                if(driveTimes.equals("am")){
                    plan.setSendTime(DateUtils.splicingTime(date, witRoute.getStartAmTime()));//发车时间
                }else {
                    plan.setSendTime(DateUtils.splicingTime(date, witRoute.getStartPmTime()));//发车时间
                }
                planService.insertWitPlan(plan);
                for(WitAppoint witAppoint : witBus.getWitAppointList()){
                    witAppoint.setBusId(witBus.getBusId());
                    witAppoint.setBusModel(witBus.getBusModel());
                    witAppoint.setBusNumber(witBus.getBusNumber());
                    witAppoint.setDriverUserId(plan.getDriverUserId());
                    witAppoint.setDriverUserName(plan.getDriverUserName());
                    witAppoint.setDriverUserPhone(user.getPhonenumber());
                    witAppoint.setPlanId(plan.getPlanId());
                    appointService.updateWitAppoint(witAppoint);
                }
            }
        }

    }

    /**
     * 平均分车策略,把所有预约平均分到每一个车内
     * 结果封装到每个排班对象内
     */
    public void averageBus(List<WitBus> witBusList, List<WitAppoint> witAppointList){
        int count = 0;
        for(WitAppoint appoint : witAppointList){
            if(count >= witBusList.size()){
                count = 0;
            }
            witBusList.get(count).getWitAppointList().add(appoint);
            count++;
        }
    }

    /**
     * 获取该路线需要车数量(根据预约数量决定)
     * @return
     */
    private List<WitBus> listNeedBusCount(List<WitAppoint> appointList){
        List<WitBus> needBusCount = new ArrayList<WitBus>();
        int seatReservation = this.getSeatReservation();//车座位预留数
        int appointSize = appointList.size();
        Long routeId = appointList.get(0).getRouteId();
        while (true){
            WitBus witBus = this.getBus(routeId);//可能存在没有车,或者车不够了
            if(witBus == null){
                return needBusCount;
            }
            if(appointSize > witBus.getFullLoad() - seatReservation){
                appointSize = appointSize - (witBus.getFullLoad() - seatReservation);
                needBusCount.add(witBus);
            }else {
                needBusCount.add(witBus);
                break;
            }
        }
        return needBusCount;
    }

    /**
     * 按照路线ID查今日所有预约内容
     * 早 am，晚 pm
     * @return
     */
    private List<WitAppoint> getAllAppoint(Long routeId, String driveTime, Date date){
        WitAppoint appoint = new WitAppoint();
        appoint.setAppointStatus(0);//已预约
        appoint.setTempStatus(0);//临时预约不参与排班
        appoint.setRouteId(routeId);
        appoint.setGotoTime(date);
        appoint.setDriveTime(driveTime);
        return appointService.selectWitAppointList(appoint);
    }

    /**
     * 获取所有路线
     * @return
     */
    private List<WitRoute> getAllRoute(){
        WitRoute route = new WitRoute();
        route.setRouteStatus(0);
        return routeService.selectWitRouteList(route);
    }

    /**
     * 获取座位预留数
     * @return
     */
    private int getSeatReservation(){
        String seatReservation = configService.selectConfigByKey("seat_reservation");
        try{
            return Integer.parseInt(seatReservation);
        }catch (Exception e){
            return 5;//没配置就默认给与5个预留位
        }
    }

    /**
     * 获取一辆车
     * 使用过去七天内(包括今天)出车次数少的,按车辆分组,大家跑自己熟悉的路线
     * @return
     */
    private WitBus getBus(Long routeId){
        String key = "bus_plan_count_" + routeId;
        List<WitBus> witBusList = redisCache.getCacheObject(key);
        if(witBusList == null){
            witBusList = busService.selectBusByPlanCount(routeId);
            witBusList.sort((o1,o2) -> o1.getPlanList().size() - o2.getPlanList().size());
        }
        if(witBusList.size() == 0){
            return null;
        }
        WitBus bus = witBusList.get(0);
        witBusList.remove(bus);
        redisCache.setCacheObject(key, witBusList, 2, TimeUnit.HOURS);//2个小时过期
        return bus;
    }

    private SysUser getDriverUser(Long userId){
        SysUser sysUser = userService.selectUserById(userId);
        if(sysUser != null){
            return sysUser;
        }
        return new SysUser();//可以不设置昵称,但不能报错,防止个人原因删除用户
    }

    /**
     * 是否可以排班
     * @return
     */
    private boolean isPlan(Long routeId, String driveTime, Date date){
        WitPlan witPlan = new WitPlan();
        witPlan.setSendTime(date);
        witPlan.setRouteId(routeId);
        witPlan.setDriveTime(driveTime);
        witPlan.setPlanStatus(0);
        List<WitPlan> witPlanList = planService.selectWitPlanList(witPlan);
        if(witPlanList.size() == 0){
            return false;
        }
        return true;
    }
}
